package cn.px.service.upms.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.px.common.enums.ResultCode;
import cn.px.common.exception.BusinessException;
import cn.px.common.util.BeanConverterUtil;
import cn.px.common.util.IdGeneratorUtils;
import cn.px.common.util.ListUtils;
import cn.px.dao.dto.upms.SysMenuDTO;
import cn.px.dao.entity.upms.SysMenu;
import cn.px.dao.entity.upms.SysRoleMenu;
import cn.px.dao.mapper.upms.SysMenuMapper;
import cn.px.dao.mapper.upms.SysRoleMenuMapper;
import cn.px.service.base.impl.BaseServiceImpl;
import cn.px.service.upms.SysMenuService;
import cn.px.service.util.ExecuteSql;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description 菜单 service 实现类
 * @author 品讯科技
 * @date 2024-08
 * @Version Copyright (c) 2019,北京乾元坤和科技有限公司 All rights reserved.
 */
@Service("sysMenuService")
@AllArgsConstructor
public class SysMenuServiceImpl extends BaseServiceImpl<SysMenuMapper, SysMenu, SysMenuDTO> implements SysMenuService {

    private final SysRoleMenuMapper sysRoleMenuMapper;

    @Override
    public List<SysMenu> selectMenuSortByRoleId(String... roleIds) {
        return this.selectMenuSortByRoleId(Arrays.asList(roleIds));
    }

    @Override
    public List<SysMenu> selectMenuSortByRoleId(List<String> roleIds) {
        Weekend<SysRoleMenu> weekend = new Weekend<>(SysRoleMenu.class);
        weekend.weekendCriteria().andIn(SysRoleMenu::getRoleId, roleIds);
        List<SysRoleMenu> roleMenus = sysRoleMenuMapper.selectByExample(weekend);
        if (roleMenus.isEmpty()) {
            return new ArrayList<>(0);
        }
        Weekend<SysMenu> menuWeekend = new Weekend<>(SysMenu.class);
        List<String> menuIds = roleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
        menuWeekend.weekendCriteria().andIn(SysMenu::getMenuId, menuIds);
        menuWeekend.setOrderByClause(" sort ASC");
        return mapper.selectByExample(menuWeekend);
    }

    @Override
    public void dropMenu(String menuId, SysMenuDTO sysMenuDTO) {
        Boolean dropToGap = sysMenuDTO.getDropToGap();
        SysMenu sysMenu = mapper.selectByPrimaryKey(sysMenuDTO);
        SysMenu update = new SysMenu();
        update.setMenuId(menuId);
        update.setSort(sysMenuDTO.getSort());
        // true是同级  不包含，是放在外部的，false与空是放在里面的
        if (dropToGap != null && dropToGap) {
            update.setParentId(sysMenu.getParentId());
            update.setParentName(sysMenu.getParentName());
        } else {
            update.setParentId(sysMenu.getMenuId());
            update.setParentName(sysMenu.getTitle());
        }
        mapper.updateByPrimaryKeySelective(update);
    }

    @Override
    public void copyMenu(String menuId) {
        List<SysMenu> saveList = ListUtils.newArrayList();
        SysMenu sysMenu = mapper.selectByPrimaryKey(menuId);
        SysMenu saveSysMenu = BeanConverterUtil.copyObjectProperties(sysMenu, new SysMenu());
        saveSysMenu.setMenuId(IdGeneratorUtils.getObjectId());
        saveSysMenu.setName(saveSysMenu.getName() + "copy");
        saveSysMenu.setTitle(saveSysMenu.getTitle() + "copy");
        saveList.add(saveSysMenu);
        List<SysMenu> child = this.getChild(menuId, saveSysMenu.getMenuId());
        saveList.addAll(child);
        mapper.insertListforComplex(saveList);

    }

    @Override
    public void deleteAllByMenuId(String menuId, Boolean deleteAll) {
        if (!deleteAll) {
            this.deleteByPrimaryKey(menuId);
            return;
        }
        List<SysMenu> childList = getChild(menuId);
        List<String> menuIds = childList.stream().map(SysMenu::getMenuId).collect(Collectors.toList());
        menuIds.add(menuId);
        Weekend<SysMenu> weekend = new Weekend<>(SysMenu.class);
        weekend.weekendCriteria().andIn(SysMenu::getMenuId, menuIds);
        mapper.deleteByExample(weekend);
    }

    private List<SysMenu> getChild(String menuId) {
        List<SysMenu> saveList = ListUtils.newArrayList();
        // 获得该菜单下所有子菜单
        Weekend<SysMenu> weekend = new Weekend<>(SysMenu.class);
        weekend.weekendCriteria().andEqualTo("parentId", menuId);
        List<SysMenu> sysMenus = mapper.selectByExample(weekend);
        if (CollectionUtil.isEmpty(sysMenus)) {
            return saveList;
        }
        sysMenus.forEach(item -> {
            saveList.add(item);
            List<SysMenu> child = this.getChild(item.getMenuId());
            if (CollectionUtil.isNotEmpty(child)) {
                saveList.addAll(child);
            }
        });
        return saveList;
    }

    private List<SysMenu> getChild(String oldMenuId, String newMenuId) {
        List<SysMenu> saveList = ListUtils.newArrayList();
        // 获得该菜单下所有子菜单
        Weekend<SysMenu> weekend = new Weekend<>(SysMenu.class);
        weekend.weekendCriteria().andEqualTo("parentId", oldMenuId);
        List<SysMenu> sysMenus = mapper.selectByExample(weekend);
        if (CollectionUtil.isEmpty(sysMenus)) {
            return saveList;
        }
        sysMenus.forEach(item -> {
            SysMenu saveItem = BeanConverterUtil.copyObjectProperties(item, new SysMenu());
            saveItem.setMenuId(IdGeneratorUtils.getObjectId());
            saveItem.setName(saveItem.getName() + "copy");
            saveItem.setTitle(saveItem.getTitle() + "copy");
            saveItem.setParentId(newMenuId);
            saveList.add(saveItem);
            List<SysMenu> child = this.getChild(item.getMenuId(), saveItem.getMenuId());
            if (CollectionUtil.isNotEmpty(child)) {
                saveList.addAll(child);
            }
        });
        return saveList;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modModelByDTO(SysMenuDTO model) {
        super.modModelByDTO(model);
        Weekend<SysMenu> weekend = new Weekend<>(SysMenu.class);
        weekend.weekendCriteria().andEqualTo("parentId", model.getMenuId());
        SysMenu update = new SysMenu();
        update.setParentName(model.getName());
        mapper.updateByExampleSelective(update, weekend);
    }

    @Override
    public void deleteByPrimaryKey(String id) {
        Weekend<SysMenu> weekend = new Weekend<>(SysMenu.class);
        weekend.weekendCriteria().andEqualTo("parentId", id);
        int count = mapper.selectCountByExample(weekend);
        if (count > 0) {
            throw new BusinessException(ResultCode.DELETE_HAS_CHILDREN.getDescription());
        }
        super.deleteByPrimaryKey(id);
    }

    @Override
    public List<SysMenu> getModelListByDTO(SysMenuDTO model) {
        Weekend<SysMenu> weekend = new Weekend<>(SysMenu.class);
        WeekendCriteria<SysMenu, Object> sysMenuObjectWeekendCriteria = weekend.weekendCriteria();
        ExecuteSql.executeNotBlank(model.getClientId(), () ->
                sysMenuObjectWeekendCriteria.andEqualTo(SysMenu::getClientId, model.getClientId()));


        weekend.setOrderByClause(" sort ASC");
        return mapper.selectByExample(weekend);
    }
}
